﻿using Dapper.Library;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Dapper.MySql.Library
{
    internal static class ResolveExpression
    {
        public static SymbolInfo SymbolInfo;

        public static void InitOption(SymbolInfo symbolInfo)
        {
            SymbolInfo = symbolInfo;
        }

        /// <summary>
        /// 拼装OrderBy语句
        /// </summary>
        /// <param name="orderbyExpressionDic"></param>
        /// <returns></returns>
        public static string ResolveOrderBy(Dictionary<OrderByType, string> orderbyDic)
        {
            if (orderbyDic == null || !orderbyDic.Any())
                return "";

            var orderByList = orderbyDic.Select(a =>
            {
                var columnName = a.Value;//((MemberExpression)a.Value.Body).Member.GetColumnAttributeName();
                return SymbolInfo.CombineFieldName(columnName) + (a.Key == OrderByType.Asc ? " ASC " : " DESC ");
            }).ToList();

            if (!orderByList.Any())
                return "";

            return "ORDER BY " + string.Join(",", orderByList);
        }

        /// <summary>
        /// 拼装Where语句
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public static WhereExpression ResolveWhere(LambdaExpression whereExpression, string prefix = null)
        {
            var where = new WhereExpression(whereExpression, prefix, SymbolInfo);

            return where;
        }

        /// <summary>
        /// 拼装Where语句
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static UpdateEntityWhereExpression ResolveWhere(object obj)
        {
            var where = new UpdateEntityWhereExpression(obj, SymbolInfo);
            where.Resolve();
            return where;
        }

        /// <summary>
        /// 拼装Where语句
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="updateTableAsName">需要更新的表的别名</param>
        /// <returns></returns>
        public static UpdateEntityWhereExpression ResolveWhereNotExists(object obj,string updateTableAsName="")
        {
            var where = new UpdateEntityWhereExpression(obj, SymbolInfo,updateTableAsName);
            where.Resolve();
            return where;
        }

        /// <summary>
        /// 拼装Select语句
        /// </summary>
        /// <param name="propertyInfos"></param>
        /// <param name="selector"></param>
        /// <param name="topNum">MySql不支持Top</param>
        /// <returns></returns>
        public static string ResolveSelect(PropertyInfo[] propertyInfos, LambdaExpression selector, int? topNum)
        {
            //select * from tablename order by orderfield desc/asc limit 0,15
            var selectFormat =" SELECT {0} ";
            var selectSql = "";

            if (selector == null)
            {
                var propertyBuilder = new StringBuilder();
                foreach (var propertyInfo in propertyInfos)
                {
                    if (propertyBuilder.Length > 0)
                        propertyBuilder.Append(",");
                    propertyBuilder.AppendFormat($"{SymbolInfo.CombineFieldName(propertyInfo.GetColumnAttributeName()) } AS {SymbolInfo.CombineFieldName(propertyInfo.Name)}");
                }
                selectSql = string.Format(selectFormat, propertyBuilder);
            }
            else
            {
                var nodeType = selector.Body.NodeType;
                if (nodeType == ExpressionType.MemberAccess)
                {
                    var columnName = ((MemberExpression)selector.Body).Member.GetColumnAttributeName();
                    selectSql = string.Format(selectFormat, SymbolInfo.CombineFieldName(columnName));
                }
                else if (nodeType == ExpressionType.MemberInit)
                {
                    var memberInitExpression = (MemberInitExpression)selector.Body;
                    selectSql = string.Format(selectFormat, string.Join(",", memberInitExpression.Bindings.Select(a => SymbolInfo.CombineFieldName(a.Member.GetColumnAttributeName()))));
                }
            }

            return selectSql;
        }

        /// <summary>
        /// 拼装获取先Update-再Select语句
        /// </summary>
        /// <param name="propertyInfos"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static string ResolveSelectOfUpdate(PropertyInfo[] propertyInfos, LambdaExpression selector)
        {
            var selectSql = "";

            if (selector == null)
            {
                var propertyBuilder = new StringBuilder();
                foreach (var propertyInfo in propertyInfos)
                {
                    if (propertyBuilder.Length > 0)
                        propertyBuilder.Append(",");
                    propertyBuilder.AppendFormat($"{ SymbolInfo.CombineFieldName(propertyInfo.GetColumnAttributeName())} { SymbolInfo.CombineFieldName(propertyInfo.Name)}");
                }
                selectSql = propertyBuilder.ToString();
            }
            else
            {
                var nodeType = selector.Body.NodeType;
                if (nodeType == ExpressionType.MemberAccess)
                {
                    var columnName = ((MemberExpression)selector.Body).Member.GetColumnAttributeName();
                    selectSql = SymbolInfo.CombineFieldName(columnName);
                }
                else if (nodeType == ExpressionType.MemberInit)
                {
                    var memberInitExpression = (MemberInitExpression)selector.Body;
                    selectSql = string.Join(",", memberInitExpression.Bindings.Select(a =>SymbolInfo.CombineFieldName(a.Member.GetColumnAttributeName())));
                }
            }
            return selectSql;
        }

        /// <summary>
        /// 拼装Sum语句
        /// </summary>
        /// <param name="propertyInfos"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static string ResolveSum(PropertyInfo[] propertyInfos, LambdaExpression selector)
        {
            if (selector == null)
                throw new ArgumentException("selector");
            var selectSql = "";

            var nodeType = selector.Body.NodeType;
            switch (nodeType)
            {
                case ExpressionType.MemberAccess:
                    var columnName = ((MemberExpression)selector.Body).Member.GetColumnAttributeName();
                    selectSql = $" SELECT IFNULL(SUM({SymbolInfo.CombineFieldName(columnName)}),0)  ";
                    break;
                case ExpressionType.MemberInit:
                    throw new Exception("不支持该表达式类型");
            }

            return selectSql;
        }

        /// <summary>
        /// 拼装Update语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="updateExpression"></param>
        /// <param name="updateTableAsName">更新表别名</param>
        /// <returns></returns>
        public static UpdateExpression ResolveUpdate<T>(Expression<Func<T, T>> updateExpression,string updateTableAsName="")
        {
            return new UpdateExpression(updateExpression, SymbolInfo, updateTableAsName);
        }

        /// <summary>
        ///SQLServer 默认情况下一个事务修改了某个值，在这个事务提交前，是阻塞其他连接来读取这个修改中的值的，如果加nolock读取到的是修改后为提交的值（也就是脏读，因为可能这个值最终会回滚）
        ///MySQL 默认情况下，一个事务修改了某个值，在这个事务提交前，不阻塞其他连接来读取这个修改中的值，并且读取到的是修改前的值。 
        /// </summary>
        /// <param name="nolock"></param>
        /// <returns></returns>
        public static string ResolveWithNoLock(bool nolock)
        {
            return "";
        }
    }
}
